package dll_test;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JFrame;

public class KinectHandler {
	
	static {
		System.loadLibrary("My_Kinect_Project");
	}
	private static KinectHandler instance = new KinectHandler();
	private KinectHandler(){
	}
	static public KinectHandler getInstance(){
		return instance;
	}
	
	private int imageFrameLength;
	private int imageFramePitch;
	private int imageFrameHeight;
	private int imageFrameWidth;
    private int imagePixelNum;
    
    private int depthFrameLength;
    private int depthFramePitch;
    private int depthFrameHeight;
    private int depthFrameWidth;
    private int depthPixelNum;
    private boolean isContainIndex;
    
	private int[] depthFrame;
	private int[] depthFrameRGB;
	private byte[] depthIndex;
			
	private byte[] imageFrame;
	private int[] intImageFrame;

	private Socket imageSocket;
	
	private native boolean initKinect();
	private native boolean destroyKinect();
	private native boolean checkKinect();
	private native boolean isContainIndex();
	

	
	private native int getImageLength();
	private native int getDepthLength();
	private native int getImagePitch();
	private native int getDepthPitch();
	
	public native boolean getImageFrame(byte[] colorFrame, int length);
	public native boolean getDepthFrame(int[] depthFrame,  int length);
	public native boolean setAngle(int angle);
    public native int getAngle();
	
	public boolean init()
	{
		if(initKinect())
		{

			imageFrameLength = getImageLength();
			imageFramePitch = getImagePitch();
			imageFrameHeight = imageFrameLength / imageFramePitch;
			imageFrameWidth = imageFramePitch / 4;
			imagePixelNum = imageFrameLength / 4;
			imageFrame = new byte[imageFrameLength];
			intImageFrame = new int[imagePixelNum];
			
			depthFrameLength = getDepthLength();
			depthFramePitch = getDepthPitch();
			depthFrameHeight = depthFrameLength / depthFramePitch;
			depthFrameWidth = depthFramePitch / 2; // as size of USHORT is 2 bytes
			depthPixelNum = depthFrameLength / 2;
			depthFrame = new int[depthPixelNum];
			depthIndex = new byte[depthPixelNum];
			depthFrameRGB = new int[depthPixelNum];
			isContainIndex = isContainIndex();
			
			
			return true;
		}
		return false;
	}

	public boolean destory(){
		return destroyKinect();
	}
	
	public boolean isInitiated()
	{
		return checkKinect();
	}
	

	public boolean updateImageFrame(){
		return getImageFrame(imageFrame, imageFrameLength);
	}
	
	public byte[] getLocalImageFrame(){
		return imageFrame;
	}
	
	public BufferedImage getImageFrameInBufferedImage()
	{
	    // combine byte image to int image	
		for (int j = 0; j < imagePixelNum; j++) {
			int startIdx = 4 * j;
			intImageFrame[j] = (imageFrame[startIdx] & 0xFF)   // B
					| (imageFrame[startIdx + 1] & 0xFF) << 8   // G
					| (imageFrame[startIdx + 2] & 0xFF) << 16;  // R
//					| (0xff << 24);                            // A
		}
		
		BufferedImage img = new BufferedImage(imageFrameWidth, imageFrameHeight, BufferedImage.TYPE_INT_RGB);
		img.setRGB(0, 0, imageFrameWidth, imageFrameHeight, intImageFrame, 0, imageFrameWidth);
		return img;
	}
	
	public boolean updateDepthFrame(){
		return getDepthFrame(depthFrame, depthFrameLength);
	}
	
	public int[] getLocalDepthFrame(){
		return depthFrame;
	}
	
	public BufferedImage getDepthFrameInBufferedImage() {

		int dis;
		int idx;
		int density;
		if (isContainIndex) {
			for (int i = 0; i < depthPixelNum; i++) {
			    idx = depthFrame[i] & 0x7;
			    depthIndex[i] = (byte)idx;
			    
			    dis = depthFrame[i] >>> 3;
			    density =(int) (((float)(4000 - dis)) * 256 / (4000 - 800));
			    if(density >= 0 && density < 256){
			    	depthFrameRGB[i] = density | density << 8 | density << 16;
			    }
			    else if(density > 256)
			    	depthFrameRGB[i] = 0xffffff;
			    else 
			    	depthFrameRGB[i] = 0;
			}
			
		} else {
			for (int i = 0; i < depthPixelNum; i++) {
				depthIndex[i] = -1;
				
				dis = depthFrame[i];
			    density =(int) (((float)(4000 - dis)) * 256 / (4000 - 800));
			    if(density >= 0 && density < 256){
			    	depthFrameRGB[i] = density | density << 8 | density << 16;
			    }
			    else if(density > 256)
			    	depthFrameRGB[i] = 0xffffff;
			    else 
			    	depthFrameRGB[i] = 0;
			}
		}
		
		BufferedImage img = new BufferedImage(depthFrameWidth,
				depthFrameHeight, BufferedImage.TYPE_INT_RGB);
		img.setRGB(0, 0, depthFrameWidth, depthFrameHeight, depthFrameRGB, 0,
				depthFrameWidth);
		return img;
	}


	public static void main(String[] args) {
		KinectHandler kh = new KinectHandler();
		if (kh.init()) {
			kh.updateImageFrame();
			kh.updateDepthFrame();
/*			
			BufferedImage img = kh.getImageFrameInBufferedImage();
			BufferedImage depthImg = kh.getDepthFrameInBufferedImage();
			

			
			JFrame colorFrame = new JFrame("Color Image From Kinect");
			colorFrame.setBounds(0, 0, img.getWidth(), img.getHeight());
			colorFrame.setVisible(true);
			
			JFrame depthFrame = new JFrame("Depth Image From Kinect");
			depthFrame.setBounds(0, 0, depthImg.getWidth(),
					depthImg.getHeight());
			depthFrame.setVisible(true);

			Graphics2D g = (Graphics2D) colorFrame.getContentPane()
					.getGraphics();
			g.drawImage(img, null, 0, 0);
			
			Graphics2D depthG = (Graphics2D) depthFrame.getContentPane()
					.getGraphics();
			depthG.drawImage(depthImg, null, 0, 0);
*/
			JFrame colorFrame = new JFrame("Color Image From Kinect");
			colorFrame.setBounds(0, 0, 640, 480);
			colorFrame.setVisible(true);
			int longestLineCharNum  = 0;
			BufferedInputStream in;
            try {
				Socket clientSock = new Socket("localhost", 2011);
				System.out.println("Connected to localhost at port 2011");
				in = new BufferedInputStream(clientSock.getInputStream());

				for (int i = 0; i < 20; i++) {
					in.
					in.read(kh.imageFrame);
					// System.out.println(xml);
					BufferedImage img = kh.getImageFrameInBufferedImage();
					Graphics2D g = (Graphics2D) colorFrame.getContentPane()
							.getGraphics();
					g.drawImage(img, null, 0, 0);
				}
				
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            System.out.println(longestLineCharNum);
			kh.destory();
		}
		return;
		
		/*
		if (kh.initKinect()) {
			kh.imageFrameLength = kh.getImageLength();
			kh.imageFramePitch = kh.getImagePitch();
			kh.imageFrameHeight = kh.imageFrameLength / kh.imageFramePitch;

			kh.imageFrame = new byte[kh.imageFrameLength];
			int[] intFrame = new int[kh.imageFrameLength / 4];
			byte[] byteFrame = kh.imageFrame;
			
			int height = kh.imageFrameHeight;
			int width = kh.imageFramePitch / 4;
			int pitch = kh.imageFramePitch;
			int length = kh.imageFrameLength;
			int pixelNum = length / 4;

			BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
			JFrame frame = new JFrame("Image From Kinect");
			frame.setBounds(0, 0, img.getWidth(), img.getHeight());
			frame.setVisible(true);
			Graphics2D g = (Graphics2D) frame.getRootPane().getGraphics();

			for (int i = 0; i < 5; i++) {
				kh.getImageFrame(kh.imageFrame, kh.imageFrameLength);

				for (int j = 0; j < pixelNum; j++) {
					int startIdx = 4 * j;
					intFrame[j] = (byteFrame[startIdx] & 0xFF)
							| (byteFrame[startIdx + 1] & 0xFF) << 8
							| (byteFrame[startIdx + 2] & 0xFF) << 16 | (0xff << 24);
				}

				img.setRGB(0, 0, width, height, intFrame, 0, width);
				g.drawImage(img, null, 0, 0);
			}
			boolean res = kh.destroyKinect();
			return;
		}
		*/
	}
}
